package com.hsxc.cdz.monitor.FSM;

import com.hsxc.cdz.base.bean.Bill;
import com.hsxc.cdz.base.bean.Reserv;
import com.hsxc.cdz.base.util.TimeFormatter;
import com.hsxc.cdz.mgmt.GlobalManager;
import com.hsxc.cdz.monitor.FSM.PileMemState.Status;
import com.hsxc.cdz.monitor.bean.FeeRate;
import com.hsxc.cdz.monitor.bean.pile.v1_33.ChargeData;
import com.hsxc.cdz.monitor.executor.ServerExecutor;
import com.hsxc.cdz.trans.bill.CacheTrade;
import com.hsxc.cdz.trans.bill.CacheTrade.TradeStatus;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;

/**
 * 充电桩缓存对象
 *
 * @author 刘力文
 */
public class CachePile implements CachePileIntf {

    private Logger logger = LoggerFactory.getLogger(CachePile.class);
    // =================================================================================
    // 缓存电桩对外状态
    public static final int PILE_STATUS_LOCKED = 0;// 表示已经被占用
    public static final int PILE_STATUS_FAULT = 1; // 表示电桩故障
    public static final int PILE_STATUS_UNINSERT = 2;// 表示未插入充电接口
    public static final int PILE_STATUS_INSERTED = 3;// 表示已经插入充电接口

    public static final int SUCCESS = 0;
    public static final int FAILURE = 1;
    public static final int ERR_DATA = 2;
    // ==============================================================================
    // 缓存电桩属性
    private String operator; // 运营商
    private String address; // 设备地址即pileid
    private String station; // 充电站
    private Channel channel; // 连接通道
    public PileMemState state; // 内置状态机对象
    private String protocolVersion;// 协议版本
    private int pileType;// 电桩类型

    private boolean park; // 停车位
    private int count = 0; // 电度表计数
    private boolean isInserted = false; // 是否连枪
    private String fault = "00"; // 00:正常，01：急停故障，02：电表故障，03：接触器故障，04：读卡器故障
    // 05：内部过温故障 06：连接器故障，07：绝缘故障，08：电流故障，09：电压故障，
    // 0A其他故障
    private boolean reserve = false;
    // 遥测数据
    private int voltage = 0; // 充电电压
    private int current = 0; // 充电电流
    private int hours = 0; // 充电小时
    private int minutes = 0; // 充电分钟
    private int power = 0; // 充电功率
    // 遥脉数据
    private int electricity = 0; // 充电电量
    private int money = 0; // 充电金额

    private ChargeData chargeData;// 直流桩会有上传充电数据

    private FeeRate feeRate;

    // 构造函数
    public CachePile(String operator, String address) {
        // 初始状态为IDLE
        this.state = new PileMemStateIdle(this);
        this.address = address;
        this.operator = operator;
        this.isInserted = false;

    }

    public CachePile(String operator, String address, PileMemState pileMemState) {
        this.state = pileMemState;
        this.address = address;
        this.operator = operator;
        this.isInserted = false;
    }

    // 1，actions on FSM
    // ===========================================================================
    @Override
    public int fault() {
        return state.fault();
    }

    @Override
    public int recovery() {
        return state.recovery();
    }

    @Override
    public int reserve(int chargePort, String cardNum, int duration) {
        return state.reserve(chargePort, cardNum, duration, this.address, this.operator, this.getProtocolVersion(),
                this.getPileType());
    }

    @Override
    public boolean confirmReserv(int port, String cardNum, String startTimeByPile) {
        // 不同协议的处理
        if (this.getProtocolVersion().equals("0121") || this.getPileType() == 0) {
            // 交流桩无需处理预约确认
            state.confirmReserv_jiaoliu(port, cardNum, this.getAddress(), this.getOperator(), this.getProtocolVersion(), this.getPileType());
            return true;
        } else if (this.getProtocolVersion().equals("0133") || this.getPileType() == 1) {
            // 查找该用户存在的唯一一个正在进行中的预约
            Reserv reserv = GlobalManager.cacheReservManager.queryReserv(cardNum, this.getAddress());
            // 根据预约开始结束时间计算预约时长
            String startTime = reserv.getReservStartTime();
            String stopTime = reserv.getReservStopTime();
            Calendar start = TimeFormatter.dateFromString(startTime);
            Calendar stop = TimeFormatter.dateFromString(stopTime);
            long duration = start.getTimeInMillis() - stop.getTimeInMillis();
            // 获取真正的预约开始时间并计算结束时间
            // String trueStartTime = reservPileMsg.getResStartTime();
            Calendar trueStopCalendar = Calendar.getInstance();
            trueStopCalendar.add(Calendar.SECOND, (int) duration / 1000 / 60);
            String trueStopTime = TimeFormatter.strFromCalendar(trueStopCalendar);
            reserv.setReservStartTime(startTimeByPile);
            reserv.setReservStopTime(trueStopTime);
            int i = GlobalManager.reservManager.updateReserv(reserv.getResNo(), reserv.getReservStartTime(),
                    reserv.getReservStopTime(), true);
            if (i == 1) {
                logger.info("update reserv successed");
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }

    }

    @Override
    public int reservationCancel(int port, String cardNum) {
        // TODO Auto-generated method stub
        return state.reservationCancel(port, cardNum, this.address, this.operator, this.getProtocolVersion(),
                this.getPileType());
    }

    @Override
    public boolean confirmReservCancelled(int port, String cardNum) {
        // 找到活跃的预约并修改数据库预约记录
//        Reserv reserv = GlobalManager.cacheReservManager.queryReserv(cardNum, this.getAddress());
//        int i = GlobalManager.reservManager.updateReserv(reserv.getResNo(), false, Reserv.RESERV_STATE_CANCELL);
//        int j = GlobalManager.cacheReservManager.removeReserv(reserv.getResNo());
//        if (i == 1 && j == 0) {
//            logger.info("Reserving Cancelling-database update success-cache delete success");
//            return true;
//        }
        return false;
    }

    @Override
    public int lock() {
        // TODO Auto-generated method stub
        return state.lock();
    }

    @Override
    public int unlock() {
        // TODO Auto-generated method stub
        return state.unlock();
    }

    public FeeRate getFeeRate() {
        return feeRate;
    }

    public void setFeeRate(FeeRate feeRate) {
        this.feeRate = feeRate;
    }

    @Override
    public int chargeStart(int port, int startWay, int ctrlWay, int stopWay, double limitData, String onTimeStart,
                           String userNO) {

        if (this.getProtocolVersion().equals("0121") || this.getPileType() == 0) {
            return state.chargeStart_jiaoliu(port, startWay, ctrlWay, stopWay, limitData, onTimeStart, userNO,
                    this.getAddress(), this.getOperator(), this.getProtocolVersion(), this.getPileType());
        } else if (this.getProtocolVersion().equals("0133") || this.getPileType() == 1) {
            return state.chargeStart_zhiliu(port, startWay, ctrlWay, stopWay, limitData, onTimeStart, userNO,
                    this.getAddress(), this.getOperator(), 10, 10, this.getProtocolVersion(), this.getPileType());
        } else {
            return 1;
        }

    }

    @Override
    public boolean confirmStart(int port, int startWay, int ctrlWay, int stopWay, double limitData, String onTimeStart,
                                String userNo) {
        return this.state.confirmStart(port, this.getAddress(), userNo, this.getProtocolVersion(), this.getPileType());
    }

    @Override
    public int chargeStop(int chargePort, int control, String userNO) {
        logger.info("TRANS:Stop charging for user " + userNO + "on pile status " + this.getStatus());
        return state.chargeStop(chargePort, control, userNO, this.getProtocolVersion(), this.getPileType());
    }

    @Override
    public boolean confirmStop(int port, int controll, String userNo) {
        // TODO Auto-generated method stub
        return state.confirmStop(port, this.address, userNo, this.getProtocolVersion(), this.getPileType());
    }

    @Override
    public int heartBeatLost() {
        // TODO Auto-generated method stub
        return state.heartBeatLost();
    }

    @Override
    public int logout() {
        // TODO Auto-generated method stub
        return state.logout();
    }

    @Override
    public void changeStateCharge() {
        // TODO Auto-generated method stub
        this.state.changeStateCharge();
    }

    @Override
    public void changeStateIdle() {
        // TODO Auto-generated method stub
        this.state.changeStateIdle();
    }

    @Override
    public void changeStateReserv() {
        this.state.changeStateReservd();
    }

    @Override
    public void changeStateLocked() {
        this.state.changeStateLocked();
    }

    @Override
    public int reboot() {
        // TODO Auto-generated method stub
        return this.state.reboot();
    }

    @Override
    public void confirmReboot() {
        this.channel.close();
        GlobalManager.pileManager.delPile(this.getAddress());
    }

    @Override
    public int offLine() {
        if (state.offLine()) {
            return 0;
        } else {
            return 1;
        }
    }

    @Override
    public int rateSetting(double oneRate, double twoRate, double threeRate, double fourRate, double serviceFee, String timeRate) {

        return ServerExecutor.setRate(oneRate, twoRate, threeRate, fourRate, serviceFee, timeRate, this.getAddress(), this.getProtocolVersion()
                , this.getPileType());

    }

    @Override
    public void rateSettingConfirm() {

    }

    @Override
    public int queryRate() {
        return 0;
    }

    @Override
    public int queryRateConfirm() {
        return 0;
    }

    // 2， Transactions process
    // ===========================================================================
    public int stopTrade(String pileNo, String userNo, double electricity, double sumFee) {
        CacheTrade cacheTrade = GlobalManager.tradeManager.getTrade(pileNo, userNo);
        if (cacheTrade == null) {
            return -1;
        }
        int result = GlobalManager.tradeManager.updateTrade(cacheTrade.getTid(), TradeStatus.TRADE_STATUS_NOPAY,
                electricity, sumFee);
        logger.info("停止交易时更新交易状态-------返回值(0表示成功)---" + result);
        return result;
    }

    public int stopBill(Bill bill) {
        return GlobalManager.billManager.updateBill(bill);
    }

    // 3， Active Status update
    // ===========================================================================
    // 主动召唤电桩状态
    @Override
    public int collectStatus() {
        if (this.getProtocolVersion().equals("0121") || this.getPileType() == 0) {
            return ServerExecutor.queryState(this.address, this.getProtocolVersion(), this.getPileType());
        } else {
            // return ServerExecuterNew
        }
        // 表示没有该方法
        return 10;
    }

    // 刷新状态到前台UI，这里后面修改为websocket主动更新，目前采用前端轮询机制
    public void refreshUI() {
        // TODO:websocket
    }

    // 4， Getter & Setter for POJO
    // ===========================================================================
    // service interfaces
    public Status getStatus() {
        return this.state.status;
    }

    public String getOperator() {
        return operator;
    }

    public void setOperator(String operator) {
        this.operator = operator;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getStation() {
        return station;
    }

    public void setStation(String station) {
        this.station = station;
    }

    public Channel getChannel() {
        return channel;
    }

    public void setChannel(Channel channel) {
        this.channel = channel;
    }

    public boolean isInserted() {
        return isInserted;
    }

    public void setInserted(boolean isInserted) {
        this.isInserted = isInserted;
    }

    public String getFault() {
        return fault;
    }

    public void setFault(String fault) {
        this.fault = fault;
    }

    public boolean getReserve() {
        return reserve;
    }

    public void setReserve(boolean reserve) {
        this.reserve = reserve;
    }

    public boolean isPark() {
        return park;
    }

    public void setPark(boolean park) {
        this.park = park;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    /**
     * @return the voltage
     */
    public int getVoltage() {
        return voltage;
    }

    /**
     * @param voltage the voltage to set
     */
    public void setVoltage(int voltage) {
        this.voltage = voltage;
    }

    /**
     * @return the current
     */
    public int getCurrent() {
        return current;
    }

    /**
     * @param current the current to set
     */
    public void setCurrent(int current) {
        this.current = current;
    }

    /**
     * @return the hours
     */
    public int getHours() {
        return hours;
    }

    /**
     * @param hours the hours to set
     */
    public void setHours(int hours) {
        this.hours = hours;
    }

    /**
     * @return the minutes
     */
    public int getMinutes() {
        return minutes;
    }

    /**
     * @param minutes the minutes to set
     */
    public void setMinutes(int minutes) {
        this.minutes = minutes;
    }

    /**
     * @return the power
     */
    public int getPower() {
        return power;
    }

    /**
     * @param power the power to set
     */
    public void setPower(int power) {
        this.power = power;
    }

    /**
     * @return the electricity
     */
    public int getElectricity() {
        return electricity;
    }

    /**
     * @param electricity the electricity to set
     */
    public void setElectricity(int electricity) {
        this.electricity = electricity;
    }

    /**
     * @return the money
     */
    public int getMoney() {
        return money;
    }

    /**
     * @param money the money to set
     */
    public void setMoney(int money) {
        this.money = money;
    }

    public String getProtocolVersion() {
        return protocolVersion;
    }

    public void setProtocolVersion(String protocolVersion) {
        this.protocolVersion = protocolVersion;
    }

    public int getPileType() {
        return pileType;
    }

    public void setPileType(int pileType) {
        this.pileType = pileType;
    }

    public ChargeData getChargeData() {
        return chargeData;
    }

    public void setChargeData(ChargeData chargeData) {
        this.chargeData = chargeData;
    }

    public void init() {
        this.count = 0;
        this.voltage = 0;
        this.current = 0;
        this.power = 0;
        this.hours = 0;
        this.minutes = 0;
        this.isInserted = false;
        this.reserve = false;
        this.electricity = 0;
        this.money = 0;
    }

    @Override
    public String toString() {
        return "[" + "pileAddress" + getAddress() + "operator" + getOperator() + "status" + getStatus() + "protocol:" + getProtocolVersion() + "type" + getPileType() + "]";
    }
}